package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"sync"

	"github.com/malfunkt/hyperfox/lib/plugins/capture"
	"github.com/malfunkt/hyperfox/lib/plugins/logger"
	"github.com/malfunkt/hyperfox/lib/proxy"
)

const version = "1.9.7"

const (
	defaultAddress = `0.0.0.0`
	defaultPort    = uint(1080)
	defaultSSLPort = uint(10443)
)

var (
	flagDatabase    = flag.String("d", "", "Path to database.")
	flagAddress     = flag.String("l", defaultAddress, "Bind address.")
	flagPort        = flag.Uint("p", defaultPort, "Port to bind to.")
	flagSSLPort     = flag.Uint("s", defaultSSLPort, "Port to bind to (SSL mode).")
	flagSSLCertFile = flag.String("c", "", "Path to root CA certificate.")
	flagSSLKeyFile  = flag.String("k", "", "Path to root CA key.")
)

func main() {
	// Banner.
	log.Printf("Hyperfox v%s // https://hyperfox.org\n", version)

	// Parsing command line flags.
	flag.Parse()

	// Is SSL enabled?
	var sslEnabled bool
	if *flagSSLPort > 0 && *flagSSLCertFile != "" {
		sslEnabled = true
	}

	// User requested SSL mode.
	if sslEnabled {
		if *flagSSLCertFile == "" {
			flag.Usage()
			log.Fatal("Missing root CA certificate")
		}

		if *flagSSLKeyFile == "" {
			flag.Usage()
			log.Fatal("Missing root CA private key")
		}

		os.Setenv(proxy.EnvSSLCert, *flagSSLCertFile)
		os.Setenv(proxy.EnvSSLKey, *flagSSLKeyFile)
	}

	// Creating proxy.
	p := proxy.NewProxy()

	// Attaching logger.
	p.AddLogger(logger.Stdout{})

	// Attaching capture tool.
	res := make(chan capture.Response, 256)

	p.AddBodyWriteCloser(capture.New(res))

	// Saving captured data with a goroutine.
	go func() {
		for {
			select {
			case r := <-res:
				go func() {
					log.Printf("r: %+v", r)
				}()
			}
		}
	}()

	fmt.Println("")

	var wg sync.WaitGroup

	// Starting proxy servers.
	if *flagPort > 0 {
		wg.Add(1)
		go func() {
			defer wg.Done()
			if err := p.Start(fmt.Sprintf("%s:%d", *flagAddress, *flagPort)); err != nil {
				log.Fatalf("Failed to bind on the given interface (HTTP): ", err)
			}
		}()
	}

	if sslEnabled {
		wg.Add(1)
		go func() {
			defer wg.Done()
			if err := p.StartTLS(fmt.Sprintf("%s:%d", *flagAddress, *flagSSLPort)); err != nil {
				log.Fatalf("Failed to bind on the given interface (HTTPS): ", err)
			}
		}()
	}

	wg.Wait()
}
